/*
 * A VERY simplified shared memory class for use in a std UNIX
 * environment.  See the text for instructions on how to use
 * this class.  Copyright (c) 2002 J. S. Gray
 * 
 * Exit codes for class operations:
 *   1 - Unable to allocate memory      
 *   2 - Unable map memory
 *   3 - Could not remove shared memory
 */
#ifndef Shared_mem_h
#define Shared_mem_h
#define _GNU_SOURCE

#include <iostream>
#include <cstdio>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>

using namespace std;

template <class S_type>                // Allow for different data types
class Shared_mem {
  public:
    Shared_mem();                      // Constructor
    ~Shared_mem();                     // Destructor - remove shared memory
    void Put(const S_type);            // Assign value to shared memory
    S_type Get();                      // Return value from shared memory

  private:
    int shmid;                         // ID of shared memory
    S_type *shm_ptr;                   // Reference to shared memory
    pid_t my_pid;                      // Hang on to originator PID
};


template <class S_type>                // Generalize data type
Shared_mem<S_type>::Shared_mem() {
  my_pid = getpid();                   // Save PID of creating process
  if ((shmid = shmget(IPC_PRIVATE, sizeof(S_type), IPC_CREAT | 0660)) < 0)
    exit(1);
  if ((shm_ptr = (S_type *)shmat(shmid, NULL, 0)) == NULL)
    exit(2);
}
                                       // Remove memory if creator
template <class S_type>
Shared_mem<S_type>::~Shared_mem() {
  if (getpid() == my_pid) {
    shmdt((char *) shm_ptr);
    if (shmctl(shmid, IPC_RMID, (struct shmid_ds *) 0) == -1)
      exit(3);
  }
}
                                       // Assign value to this location
template <class S_type>
void Shared_mem<S_type>::Put(const S_type stuff) {
  *shm_ptr = stuff;
}
                                       // Retrieve value from location
template <class S_type>
S_type Shared_mem<S_type>::Get() {
  static S_type stuff;
  stuff = *shm_ptr;
  return stuff;
}
 
                                       // Force instantiation
typedef Shared_mem<int>    Shared_int;
typedef Shared_mem<char>   Shared_char;
typedef Shared_mem<float>  Shared_float;
typedef Shared_mem<double> Shared_double;

#endif
